package com.work.framework.config;

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Pointcut;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @author qinminghui
 * @description TODO
 * @date 21 16:45
 */
public class DefaultDynamicDataSourceAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {

    private Advice advice;

    private Pointcut pointcut;

    private HttpServletRequest request;

    public DefaultDynamicDataSourceAdvisor(List<String> expressionList, HttpServletRequest request) {
        this.pointcut = buildPointcut(expressionList);
        this.advice = buildAdvice();
        this.request = request;
    }

    private Advice buildAdvice() {
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                try {
                    String tenantId = (String) request.getSession().getAttribute("tenant");
                    DynamicDataSourceContextHolder.push(tenantId + "");
                    return invocation.proceed();
                } finally {
                    DynamicDataSourceContextHolder.poll();
                }
            }
        };
    }

    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }

    @Override
    public Advice getAdvice() {
        return this.advice;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        if (this.advice instanceof BeanFactoryAware) {
            ((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
        }
    }

    private Pointcut buildPointcut(List<String> expressionList) {
        ComposablePointcut composablePointcut = null;
        for (String expression : expressionList) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression(expression);
            if (composablePointcut == null) {
                composablePointcut = new ComposablePointcut((Pointcut) pointcut);
            } else {
                composablePointcut.union((Pointcut) pointcut);
            }
        }
        return composablePointcut;
    }
}
